import { Body, Controller, Get, Param, ParseIntPipe, Post, Req } from '@nestjs/common';
import { DtoPipe } from '../pipes/dto/dto.pipe';
import { OrderCardDto, OrderDto } from './dto';
import { ChargeService } from './charge.service';
import { ChargeOrderService } from '../charge-order/charge-order.service';
import { DeviceService } from '../device/device.service';
import { CacheService } from '@app/cache';
import { UtilsService } from '@app/utils';
import { ConfigureService } from '@app/configure';

@Controller('charge')
export class ChargeController {
    private startChargeResKey:string; //开始充电结果的Key
    private endChargeResKey:string; //结束充电结果的Key

    private PstartChargeResKey:string; //开始充电结果的Key
    private PendChargeResKey:string; //结束充电结果的Key

    constructor(
        private readonly service:ChargeService,
        private readonly chargOrder:ChargeOrderService,
        private readonly device:DeviceService,
        private readonly cache:CacheService,
        private readonly utils:UtilsService,
        private readonly config:ConfigureService,
    ){
        this.startChargeResKey = this.config.get('startChargeResKey')
        this.endChargeResKey = this.config.get('endChargeResKey')

        this.PstartChargeResKey = this.config.get('PstartChargeResKey')
        this.PendChargeResKey = this.config.get('PendChargeResKey')
    }



    @Get('res/:id')
    async res(@Param('id') id:string) {
        const res = await this.cache.get(this.startChargeResKey + id)
        if(!res) return this.utils.failRes()

        return this.utils.successRes(res == 'w' ? 0 : (res == 'y' ? 1 : 2))
    }

    @Get('stop/res/:id')
    async stopRes(@Param('id') id:string) {
        const res = await this.cache.get(this.endChargeResKey + id)
        if(!res) return this.utils.failRes()
        return this.utils.successRes(res == 'w' ? 0 : (res == 'y' ? 1 : 2))
    }

    @Post('order')
    async order(@Body(new DtoPipe({skipMissingProperties : false})) dto:OrderDto, @Req() { userId, user, isWx, clientSource }) {
        const { deviceId, port, chargeNumber, mode } = dto
        if(deviceId < 1 || port < 1 || chargeNumber < 0 || [0, 1, 2].includes(mode) == false) return this.utils.failRes()
        const device = await this.device.findOne({id : dto.deviceId}, ['aliProduct', 'portStatus', 'connectStatus', 'chargeType', 'stationId', 'owners', 'stationId', 'private'])
        if(!device || !device.connectStatus) return this.utils.failRes('设备离线不可用')        

        if(device.portStatus && device.portStatus[port - 1] != 0) return this.utils.failRes('枪口不可用')

        if(device.private == 1) { //私人充电
            const auth = await this.device.queryPrivateAuth(deviceId, userId)
            if(!auth) return this.utils.failRes('未授权，不可使用')
            const r = await this.service.privateCharge(userId, device, deviceId, port, mode, chargeNumber)
            if(r == false) {
                return this.utils.failRes('充电失败')
            }
            return this.utils.successRes(r)
        }else {
            if(device.stationId == 0) return this.utils.failRes()
            const lockKey = `charge:${deviceId}:${port}`
            const lock = await this.cache.set(lockKey, '1', 10, 'NX')
            if(!lock) return this.utils.failRes('枪口已被占用')
            const r = await this.service.charge(userId, device, deviceId, port, mode, chargeNumber, dto.payType, isWx, user.openid, clientSource)
            this.cache.del(lockKey)
    
            if(r == null) {
                return this.utils.failRes('充电失败')
            }else if(r == -1){
                return this.utils.failRes('余额不足')
            }else if(r == -2 || r == -3 || r == -4 || r== -5) {
                return this.utils.failRes('充电失败', {code : r})
            }else {
                return this.utils.successRes(r)
            }
        }

        
    }

    @Post('stop')
    async stop(@Body('id', ParseIntPipe) id:number, @Req() { userId }) {
        if(isNaN(id) || id <= 0) return

        const order = await this.chargOrder.findOne({ id }, ['userId', 'deviceId', 'status', 'port'])
        if(!order || order.userId != userId) return
        if(order.status == 2) return this.utils.successRes()
        if(order.status != 1) return

        const device = await this.device.findOne({id : order.deviceId}, ['connectStatus', 'aliProduct'])
        if(!device || !device.connectStatus) return this.utils.failRes('设备已掉线')

        this.cache.set(this.endChargeResKey + id, 'w', 20)
        const res = await this.service.stop(id, order.deviceId, order.port, device.aliProduct)
        if(!res || !res.body || !res.body.success) {
            return this.utils.failRes('停止失败')
        }

        return this.utils.successRes()
    }

    @Post('stop/private')
    async stopPrivate(@Body('id', ParseIntPipe) id:number) {
        if(isNaN(id) || id <= 0) return

        const record = await this.service.privateChargeRecord.findOne({
            where : {id},
            select : ['status', 'deviceId', 'port']
        })

        if(record.status != 1) return this.utils.failRes('停止失败')
        const device = await this.device.findOne({id : record.deviceId}, ['connectStatus', 'aliProduct'])
        if(!device || !device.connectStatus) return this.utils.failRes('设备已掉线')
        this.cache.set(this.PendChargeResKey + id, 'w', 20)
        const res = await this.service.stop(id + 'P', record.deviceId, record.port, device.aliProduct)
        if(!res || !res.body || !res.body.success) {
            return this.utils.failRes('停止失败')
        }
        return this.utils.successRes()
    }

    //查询私人开启充电结果
    @Get('pres/:id')
    async privateStartRes(@Param('id') id:string) {
        const res = await this.cache.get(this.PstartChargeResKey + id)
        if(!res) return this.utils.failRes()

        return this.utils.successRes(res == 'w' ? 0 : (res == 'y' ? 1 : 2))
    }

    //查询私人充电停止结果
    @Get('stop/private/res/:id')
    async stopPricateRes(@Param('id') id:string) {
        const res = await this.cache.get(this.PendChargeResKey + id)
        if(!res) return this.utils.failRes()
        return this.utils.successRes(res == 'w' ? 0 : (res == 'y' ? 1 : 2))
    }


    @Post('charge/card')
    async chargeCard(@Body(new DtoPipe({skipMissingProperties : false})) dto:OrderCardDto) {
        this.service.chargeByCard(dto.deviceId, dto.port, dto.card, dto.mode)
        return ''
    }
}
